import { def, isObject } from "../utils/index.js";
import { arrayMethods } from "./array.js";
import Dep from "./dep.js";

// 333333 利用闭包 存一个 value 对数据进行 响应式化
function defineReactify(obj, key, value, enumerable) {
    // 递归进行响应式，并判断是否有dep（对数组的方法进行处理）
    const childDep = observe(value);
    // 每个属性 都对于 一个 dep
    let dep = new Dep()
    Object.defineProperty(obj, key, {
        enumerable: !!enumerable,
        configurable: true,
        get() {
            // 依赖收集
            if (Dep.target) {
                dep.depend()
                // 如果是数组就 再依赖收集
                if (childDep) {
                    childDep.dep.depend()
                }
            }
            return value
        },
        set(newVal) {
            if (value == newVal) return;
            // 递归进行响应式（用户重新赋值一个对象的情况下）
            observe(newVal);
            value = newVal;
            // 通过依赖 更新页面
            dep.notify()
        }

    })
}

// 22222 创建一个 观察者
class Observer {
    constructor(value) {
        // 为 所有的 value 添加一个 dep，可能是对象或数组,如果是数据的话，是无法进行 .dep的，所以下面判断是数据就返回
        this.dep = new Dep()

        // 自定义 为 value 添加 _ob_ 属性，这样做 是为了 让该value无法被枚举，防止死递归
        def(value, '_ob_', this)
        // 数组要进行单独判断
        if (!Array.isArray(value)) {
            this.walk(value)
        } else {
            value.__proto__ = arrayMethods
            this.observeArray(value)
        }

    }
    walk(data) {
        // 遍历
        const keys = Object.keys(data);
        keys.forEach(key => {
            defineReactify(data, key, data[key], true)
        })
    }
    observeArray(data) {
        for (let i = 0; i < data.length; i++) {
            observe(data[i])
        }
    }
}

//  111111
export function observe(data) {
    // 如果不是对象就返回
    if (!isObject(data)) return

    // 如果数据被观测过
    if (data._ob_) return data

    // 对数据进行响应式
    return new Observer(data)
}